const Angle_step = 30.0;
let currentTime = Date.now();
function animate(angle) {
    let now = Date.now();
    let elapsed = now - currentTime;
    currentTime = now;
    let nextAngle = angle + (Angle_step * elapsed) / 1000.0;
    return nextAngle %= 360;
}

function initVertexBuffers(gl) {
    // Create a cube
    //    v6----- v5
    //   /|      /|
    //  v1------v0|
    //  | |     | |
    //  | |v7---|-|v4
    //  |/      |/
    //  v2------v3
    // Coordinates
    var vertices = new Float32Array([
        0.5, 0.5, 0.5,  - 0.5, 0.5, 0.5,   -0.5, -0.5, 0.5,    0.5, -0.5, 0.5, // v0-v1-v2-v3 front
        0.5, 0.5, 0.5,    0.5, -0.5, 0.5,    0.5,- 0.5, -0.5,    0.5, 0.5, -0.5, // v0-v3-v4-v5 right
        0.5, 0.5, 0.5,    0.5, 0.5, -0.5,  -0.5, 0.5, -0.5,  - 0.5, 0.5, 0.5, // v0-v5-v6-v1 up
      - 0.5, 0.5, 0.5,  -0.5, 0.5, -0.5,   -0.5, -0.5, -0.5,   -0.5, -0.5, 0.5, // v1-v6-v7-v2 left
       -0.5, -0.5, -0.5,    0.5,- 0.5, -0.5,    0.5, -0.5, 0.5,   -0.5, -0.5, 0.5, // v7-v4-v3-v2 down
        0.5,- 0.5, -0.5,   -0.5, -0.5, -0.5,  -0.5, 0.5, -0.5,    0.5, 0.5, -0.5  // v4-v7-v6-v5 back
    ]);
  
    // Colors
    var colors = new Float32Array([
      0, 1,   0, 0,   1, 1,  1, 0,     // v0-v1-v2-v3 front
      0, 1,   0, 0,   1, 1,  1, 0,    // v0-v3-v4-v5 right
      0, 1,   0, 0,   1, 1,  1, 0,     // v0-v5-v6-v1 up
      0, 1,   0, 0,   1, 1,  1, 0,     // v1-v6-v7-v2 left
      0, 1,   0, 0,   1, 1,  1, 0,     // v7-v4-v3-v2 down
      0, 1,   0, 0,   1, 1,  1, 0,     // v4-v7-v6-v5 back
   ]);
  
    // Normal
    var normals = new Float32Array([
      0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
      1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
      0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
     -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
      0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,  // v7-v4-v3-v2 down
      0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0   // v4-v7-v6-v5 back
    ]);
  
    // Indices of the vertices
    var indices = new Uint8Array([
       0, 1, 2,   0, 2, 3,    // front
       4, 5, 6,   4, 6, 7,    // right
       8, 9,10,   8,10,11,    // up
      12,13,14,  12,14,15,    // left
      16,17,18,  16,18,19,    // down
      20,21,22,  20,22,23     // back
   ]);
  
    // Write the vertex property to buffers (coordinates, colors and normals)
    if (!initArrayBuffer(gl, 'a_position', vertices, 3, gl.FLOAT)) return -1;
    if (!initArrayBuffer(gl, 'a_texture', colors, 2, gl.FLOAT)) return -1;
    if (!initArrayBuffer(gl, 'a_normal', normals, 3, gl.FLOAT)) return -1;
  
    // Unbind the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
  
    // Write the indices to the buffer object
    var indexBuffer = gl.createBuffer();
    if (!indexBuffer) {
      console.log('Failed to create the buffer object');
      return false;
    }
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
  
    return indices.length;
}


function initArrayBuffer(gl, attribute, data, num, type) {
    // Create a buffer object
    var buffer = gl.createBuffer();
    if (!buffer) {
        console.log('Failed to create the buffer object');
        return false;
    }
    // Write date into the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    // Assign the buffer object to the attribute variable
    var a_attribute = gl.getAttribLocation(program, attribute);
    if (a_attribute < 0) {
        console.log('Failed to get the storage location of ' + attribute);
        return false;
    }
    gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
    // Enable the assignment of the buffer object to the attribute variable
    gl.enableVertexAttribArray(a_attribute);

    return true;
}

function initTexture(gl, u_sampler, imgSrc) {
  let texture = gl.createTexture();

  let img = new Image();

  img.onload = () => {
      loadTexture(gl, texture, u_sampler, img);
  }
  img.src = imgSrc
}

function loadTexture(gl, texture,  u_sampler, img) {
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  gl.activeTexture(gl.TEXTURE0);
  // gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bindTexture(gl.TEXTURE_2D, texture);
  // gl.TEXTURE_CUBE_MAP 立方体贴图、TEXTURE_3D三位贴图、TEXTURE_2D_ARRAY二维数组贴图
  // 纹理缩小滤波器
  // 使用的图片的分辨率需要属于2的幂数，2x2 4x4 8x8 16x16 32x32 64x64 ...
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  // 水平拉伸、垂直拉伸
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

  // gl.TEXTURE_2D、二维纹理贴图 gl.TEXTURE_CUBE_MAP_POSITIVE_X:立方体映射纹理的正X面
  // level 0是基本图像等级，n级是第n个金字塔简化级
  // void gl.texImage2D(target, level, internalformat, format, type, ImageData? pixels);
  // internalformat要和format相等？？

  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
  gl.uniform1i(u_sampler, 0);

  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

}

var angleInRadians = 0;
let gl = getGlByCanvasId('canvas');
let program = getProgram();
gl.clearColor(0, 0, 0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.useProgram(program);

let n = initVertexBuffers(gl);

// 设置可视区域和观察点
let uMatMvpLocation = gl.getUniformLocation(program, 'u_mvp_matrix4');
let vpMaxtrix = new Matrix4();
vpMaxtrix.setPerspective(30, 1, 1, 100);
let cameraPos = [0, 0, 5];
//视点      观察点     指定上方向
vpMaxtrix.lookAt(...cameraPos, 0, 0, 0, 0, 1, 0);

// 设置环境光 环境设置暗一点
let uCameraPosLocation = gl.getUniformLocation(program, 'u_camera_pos');
gl.uniform3f(uCameraPosLocation, ...cameraPos);

// 法向量的变换矩阵
let normalMatrix = new Matrix4();

// 设置法向量需要的模型矩阵
let uMatModelLocation = gl.getUniformLocation(program, 'u_model_matrix4');
let uMatNormalLocation = gl.getUniformLocation(program, 'u_normal_matrix');

// 设置环境光 环境设置暗一点
let uAmbientLocation = gl.getUniformLocation(program, 'u_ambient_light_pos');
gl.uniform3f(uAmbientLocation, 0.2, 0.2, 0.2);

// 设置点光源 开灯 位置和颜色
let uLightPosLocation = gl.getUniformLocation(program, 'u_point_light_pos');
gl.uniform3f(uLightPosLocation, 2, 14, 10);

let uLightColLocation = gl.getUniformLocation(program, 'u_light_col');
gl.uniform3f(uLightColLocation, 1.0, 1.0, 1.0);

let u_sampler = gl.getUniformLocation(program, 'u_sampler');
initTexture(gl, u_sampler, '../resource/' + 'cao.jpg');

// 设置限制发光地方
function degToRad(d) {
  return d * Math.PI / 180;
}
let limit = degToRad(40);
let uLimitLocation = gl.getUniformLocation(program, 'u_limit');
gl.uniform1f(uLimitLocation, Math.cos(limit));

// 设置高光系数
let specular = 5;
let uSpecularLocation = gl.getUniformLocation(program, 'u_shiness');
gl.uniform1f(uSpecularLocation, specular);

// 设置高光颜色
let uSpecularColLocation = gl.getUniformLocation(program, 'u_specular_col');
gl.uniform3f(uSpecularColLocation, 1.0, 0.0, 0.0);

let currentAngle = 0;
setInterval(() => {
    currentAngle = animate(currentAngle);
    // 用于旋转的矩阵
    let mat4ForRotate = new Matrix4();
    mat4ForRotate.setRotate(30, 1, 3, 3);

    let mvpMaxtrix = new Matrix4();
    mvpMaxtrix.set(vpMaxtrix).multiply(mat4ForRotate);
    gl.uniformMatrix4fv(uMatMvpLocation, false, mvpMaxtrix.elements);
    gl.uniformMatrix4fv(uMatModelLocation, false, mat4ForRotate.elements);

    normalMatrix.setInverseOf(mat4ForRotate);
    normalMatrix.transpose();
    gl.uniformMatrix4fv(uMatNormalLocation, false, normalMatrix.elements);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}, 100)
